package com.example.BlockChain.service.impl;

import com.example.BlockChain.dao.TChainDataDao;
import com.example.BlockChain.entity.block.Block;
import com.example.BlockChain.entity.TChainData;
import com.example.BlockChain.service.BlockService;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.zip.ZipInputStream;

@Service
public class BlockServiceImpl implements BlockService {

    // Spring 提供的 RestTemplate，用于发送 HTTP 请求
    @Resource
    private RestTemplate restTemplate;

    // 从配置文件中读取节点的 IP 地址（`application.properties` 中的配置）
    @Value("${node.ip}")
    private String ip;

    @Resource
    private TChainDataDao chainDataDao;
    @Override
    public List<TChainData> getAllOrders(String address) {return chainDataDao.queryOrderByAddress(address);}
    @Override
    public List<String> getMerchantOrder(int type){return chainDataDao.getCode(type);}
    @Override
    public List<TChainData>getConOrder(String code){return chainDataDao.getConOrders(code);}
    @Override
    public List<TChainData> getMerandDelOrders(String code){return chainDataDao.getMerandDelOrders(code);}
    @Override
    public List<TChainData> getThreeOrders(String code){return chainDataDao.getThreeOrders(code);}
    @Override
    public void updateOperationType5(String orderid){chainDataDao.updateOperationType5(orderid);}
    @Override
    public void updateOperationType4(String orderid){chainDataDao.updateOperationType4(orderid);}

    @Transactional // 开启事务管理，确保原子性
    public void merchantAcceptOrder(String orderId) {
        // 获取当前时间作为接单时间
        LocalDateTime now = LocalDateTime.now();

        // 更新订单时间表中的商家接单时间
        int timingResult = chainDataDao.updateMerchantAcceptTime(orderId, now);
        if (timingResult == 0) {
            // 如果更新失败，抛出异常回滚事务
            throw new RuntimeException("更新订单时间失败，可能订单不存在");
        }

        // 更新区块链信息表中的操作类型
        int blockchainResult = chainDataDao.updateOperationType2(orderId, 2);
        if (blockchainResult == 0) {
            // 如果更新失败，抛出异常回滚事务
            throw new RuntimeException("更新区块链信息失败，可能订单不存在");
        }
    }

    /**
     * 根据订单类型和店铺名获取订单
     *
     * @param storeName 店铺名
     * @param type      订单类型（new, in-progress, history, all）
     * @return 符合条件的订单列表
     */
    @Override
    public List<TChainData> getOrdersByTypeAndStore(String storeName, String type) {
        // 根据type决定查询条件
        switch (type.toLowerCase()) {
            case "new":
                // 新订单：operation_type = 1
                return chainDataDao.findOrdersByStoreAndType(storeName, List.of(1));
            case "in-progress":
                // 正在进行的订单：operation_type IN (2, 4)
                return chainDataDao.findOrdersByStoreAndType(storeName, List.of(2, 4));
            case "history":
                // 历史订单：operation_type IN (3, 5)
                return chainDataDao.findOrdersByStoreAndType(storeName, List.of(3, 5));
            default:
                // 全部订单：不过滤operation_type
                return chainDataDao.findOrdersByStoreAndType(storeName, null);
        }
    }

    /**
     * 根据订单类型和店铺名获取订单
     *
     * @param type      订单类型（new, in-progress, history, all）
     * @return 符合条件的订单列表
     */
    @Override
    public List<TChainData> getDeliveryOrdersByType(String type) {
        // 根据type决定查询条件
        switch (type.toLowerCase()) {
            case "new":
                // 新订单：operation_type = 3
                return chainDataDao.getDeliveryOrdersByType(List.of(3));
            case "in-progress":
                // 正在进行的订单：operation_type = 4
                return chainDataDao.getDeliveryOrdersByType(List.of(4));
            case "history":
                // 历史订单：operation_type = 5
                return chainDataDao.getDeliveryOrdersByType(List.of(5));
            default:
                // 全部订单：不过滤operation_type
                return chainDataDao.getDeliveryOrdersByType(List.of(3,4,5));
        }
    }

    @Override
    public int updateOperationType3(String orderId, int operationType) {
        return chainDataDao.updateOperationType3(orderId, operationType);
    }



    /**
     * 从压缩输入流中解析区块对象
     *
     * @param zis ZipInputStream 压缩输入流，包含区块的 JSON 字符串
     * @return Block 返回解析后的区块对象，如果解析失败返回 null
     */
    public static Block getBlockObeject(ZipInputStream zis) {
        ByteArrayOutputStream bos = null;
        try {
            // 创建一个输出流，用于存储解压后的数据
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[512]; // 定义缓冲区大小
            int len;
            // 从压缩流中读取数据并写入到 ByteArrayOutputStream 中
            while ((len = zis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            // 将解压后的字节数组转换为字符串（JSON 格式）
            String blockStr = new String(bos.toByteArray());
            // 使用 Gson 将 JSON 字符串解析为 Block 对象
            Block block = new Gson().fromJson(blockStr, Block.class);
            return block; // 返回区块对象
        } catch (JsonSyntaxException | IOException e) {
            // 捕获 JSON 解析异常或 IO 异常，打印错误信息
            e.getMessage();
        } finally {
            // 关闭 ByteArrayOutputStream 释放资源
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.getMessage();
                }
            }
        }
        return null; // 如果解析失败，返回 null
    }

    /**
     * 从压缩输入流中读取区块文件内容并以字符串形式返回
     *
     * @param zis ZipInputStream 压缩输入流，包含区块文件内容
     * @return String 返回解压后的字符串内容，如果读取失败返回空字符串
     */
    public static String getBlockFileStr(ZipInputStream zis) {
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[512]; // 定义缓冲区大小
            int len;
            // 从压缩流中读取数据并写入到 ByteArrayOutputStream 中
            while ((len = zis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            // 将解压后的字节数组转换为字符串
            String blockfileStr = new String(bos.toByteArray());
            return blockfileStr; // 返回区块文件内容字符串
        } catch (JsonSyntaxException | IOException e) {
            // 捕获 JSON 解析异常或 IO 异常，打印错误信息
            e.getMessage();
        } finally {
            // 关闭 ByteArrayOutputStream 释放资源
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.getMessage();
                }
            }
        }
        return ""; // 如果读取失败，返回空字符串
    }

    /**
     * 从压缩输入流中读取区块的最大索引值
     *
     * @param zis ZipInputStream 压缩输入流，包含区块索引值的内容
     * @return String 返回区块的最大索引值，如果读取失败返回空字符串
     */
    public static String getMaxBlockIndexStr(ZipInputStream zis) {
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024]; // 定义缓冲区大小
            int len;
            // 从压缩流中读取数据并写入到 ByteArrayOutputStream 中
            while ((len = zis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            // 将解压后的字节数组转换为字符串
            String maxBlockIndex = new String(bos.toByteArray());
            return maxBlockIndex; // 返回最大索引值字符串
        } catch (JsonSyntaxException | IOException e) {
            // 捕获 JSON 解析异常或 IO 异常，打印错误信息
            e.getMessage();
        } finally {
            // 关闭 ByteArrayOutputStream 释放资源
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.getMessage();
                }
            }
        }
        return ""; // 如果读取失败，返回空字符串
    }
}
